package main

import (
	"context"
	"fmt"
	"go.etcd.io/etcd/clientv3"
	"time"
)

func main() {
	var (
		config         clientv3.Config
		client         *clientv3.Client
		err            error
		kv             clientv3.KV
		keys           string
		putResp        *clientv3.PutResponse // 读写操作结果
		lease          clientv3.Lease
		leaseGrantResp *clientv3.LeaseGrantResponse
		leaseid        clientv3.LeaseID

		keepResp *clientv3.LeaseKeepAliveResponse
		keepRespChan <- chan *clientv3.LeaseKeepAliveResponse

		getResp *clientv3.GetResponse
	)

	config = clientv3.Config{
		Endpoints:   []string{"127.0.0.1:2379"}, //集群列表
		DialTimeout: 5 * time.Second,
	}

	// 建立一个客户端
	if client, err = clientv3.New(config); err != nil {
		fmt.Println(err)
		return
	}

	// 申请一个 lease（租约）
	lease = clientv3.NewLease(client)

	// 申请一个10秒的租约
	if leaseGrantResp, err = lease.Grant(context.TODO(), 10); err != nil {
		fmt.Println(err)
		return
	}

	// 拿到租约ID
	leaseid = leaseGrantResp.ID

	// 上下文 5秒后停止上下文
	ctx,_ := context.WithTimeout(context.TODO(),5*time.Second)

	// 自动续租
	// 目的： 确定当前联系的稳定性，如果因为其他原因服务器挂了，那么这个值就自动掉线
	if keepRespChan,err = lease.KeepAlive(ctx,leaseid);err!= nil{
		fmt.Println(err)
		return
	}

	// 处理续约应答的协程
	go func() {
		for{
			select {
			case keepResp = <- keepRespChan:
				if keepResp == nil{
					fmt.Println("租约已经失效了")
					goto END
				}else{	// 每秒会续租一次，所以会收到一次应答
					fmt.Println("收到自动续租应答",keepResp.ID)
				}

			}
		}
		END:
	}()

	// 用于读写etcd的键值对
	kv = clientv3.NewKV(client)

	// Put一个kvs，让它与租约关联起来，从而实现10秒后自动过期
	keys = "/cron/jobs/job3";
	if putResp, err = kv.Put(context.TODO(), keys, "10", clientv3.WithLease(leaseid)); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("写入成功！", putResp.Header.Revision)

	// 定时查看一下key过期没有
	for {
		if getResp, err = kv.Get(context.TODO(), keys); err != nil {
			fmt.Println(err)
			return
		}

		if getResp.Count == 0 {
			fmt.Println(keys, "过期了")
			break
		}else{
			fmt.Println(keys,"还没有过期")
		}
		time.Sleep(2 * time.Second)
	}

}
